
inline vec4::vec4( float x0/* = 0.0f*/, float y0/* = 0.0f*/, float z0/* = 0.0f*/, float w0/* = 0.0f*/) : 
	x(x0), y(y0), z(z0), w(w0) 
{
	SLMATH_VEC_ASSERT( (*this).check() );
}

inline vec4::vec4( const vec2& v0, float z0, float w0 ) :
	x(v0.x), y(v0.y), z(z0), w(w0) 
{
	SLMATH_VEC_ASSERT( (*this).check() );
}

inline vec4::vec4( const vec3& v0, float w0 ) :
	x(v0.x), y(v0.y), z(v0.z), w(w0) 
{
	SLMATH_VEC_ASSERT( (*this).check() );
}

inline void vec4::set( float x0, float y0, float z0, float w0 )
{
	x=x0;
	y=y0;
	z=z0;
	w=w0;
	SLMATH_VEC_ASSERT( (*this).check() );
}

inline vec4& vec4::operator+=( const vec4& o )
{
	m128() = SLMATH_ADD_PS( m128(), o.m128() );
	SLMATH_VEC_ASSERT( (*this).check() );
	return *this;
}

inline vec4& vec4::operator-=( const vec4& o )
{
	m128() = SLMATH_SUB_PS( m128(), o.m128() );
	SLMATH_VEC_ASSERT( (*this).check() );
	return *this;
}

inline vec4& vec4::operator*=( float s )
{
	m128() = SLMATH_MUL_PS( m128(), SLMATH_LOAD_PS1(&s) );
	SLMATH_VEC_ASSERT( (*this).check() );
	return *this;
}

inline vec4& vec4::operator*=( const vec4& o )
{
	m128() = SLMATH_MUL_PS( m128(), o.m128() );
	SLMATH_VEC_ASSERT( (*this).check() );
	return *this;
}

inline vec4& vec4::operator/=( const vec4& o )
{
	m128() = SLMATH_DIV_PS( m128(), o.m128() );
	SLMATH_VEC_ASSERT( (*this).check() );
	return *this;
}

inline vec4& vec4::operator/=( float s )
{
	SLMATH_VEC_ASSERT( fabsf(s) >= FLT_MIN ); // s must be != 0
	
	const float invs = 1.f/s;
	m128() = SLMATH_MUL_PS( m128(), SLMATH_LOAD_PS1(&invs) );
	return *this;
}

inline vec4 vec4::operator/( float s ) const
{
	SLMATH_VEC_ASSERT( fabsf(s) >= FLT_MIN ); // s must be != 0
	const float invs = 1.f/s;
	return vec4( SLMATH_MUL_PS( m128(), SLMATH_LOAD_PS1(&invs) ) );
}

inline vec3& vec4::xyz()
{
	return *(vec3*)&x;
}

inline const vec3& vec4::xyz() const
{
	return *(const vec3*)&x;
}

inline vec4 vec4::operator*( const vec4& o ) const
{
	SLMATH_VEC_ASSERT( o.check() );
	SLMATH_VEC_ASSERT( (*this).check() );
	return vec4( SLMATH_MUL_PS( m128(), o.m128() ) );
}

inline vec4 vec4::operator/( const vec4& o ) const
{
	SLMATH_VEC_ASSERT( (*this).check() );
	SLMATH_VEC_ASSERT( fabsf(o.x) > FLT_MIN );
	SLMATH_VEC_ASSERT( fabsf(o.y) > FLT_MIN );
	SLMATH_VEC_ASSERT( fabsf(o.z) > FLT_MIN );
	SLMATH_VEC_ASSERT( fabsf(o.w) > FLT_MIN );
	return vec4( SLMATH_DIV_PS( m128(), o.m128() ) );
}

inline vec4 vec4::operator+( const vec4& o ) const
{
	SLMATH_VEC_ASSERT( o.check() );
	SLMATH_VEC_ASSERT( (*this).check() );
	return vec4( SLMATH_ADD_PS( m128(), o.m128() ) );
}

inline vec4 vec4::operator-( const vec4& o ) const
{
	SLMATH_VEC_ASSERT( o.check() );
	SLMATH_VEC_ASSERT( (*this).check() );
	return vec4( SLMATH_SUB_PS( m128(), o.m128() ) );
}

inline vec4 vec4::operator-() const
{
	SLMATH_VEC_ASSERT( (*this).check() );
	return vec4( SLMATH_SUB_PS( SLMATH_SETZERO_PS(), m128() ) );
}

inline vec4 vec4::operator*( float s ) const
{
	SLMATH_VEC_ASSERT( slm::check(s) );
	SLMATH_VEC_ASSERT( (*this).check() );
	return vec4( SLMATH_MUL_PS( m128(), SLMATH_LOAD_PS1(&s) ) );
}

inline bool vec4::operator==( const vec4& o ) const
{
	return x==o.x && y==o.y && z==o.z && w==o.w;
}

inline bool vec4::operator!=( const vec4& o ) const
{
	return !(*this == o);
}

inline float vec4::length()const
{
	const float res = sqrtf(lengthSq());
	SLMATH_VEC_ASSERT( res >= 0.f && res <= FLT_MAX );
	return res;
}

inline float vec4::lengthSq()const
{
	const float res = x*x + y*y + z*z + w*w;
	SLMATH_VEC_ASSERT( res >= 0.f && res <= FLT_MAX );
	return res;
}

inline float vec4::distance(const vec4& p1 )const
{
	return (*this - p1).length();
}

inline float vec4::distanceSq(const vec4& p1 )const
{
	return (*this - p1).lengthSq();
}

inline float vec4::dot(const vec4& b )const
{
	const float res = x*b.x + y*b.y + z*b.z + w*b.w;
	SLMATH_VEC_ASSERT( res >= -FLT_MAX && res <= FLT_MAX );
	return res;
}


inline vec4 vec4::abs()const
{
	return vec4( SLMATH_MAX_PS(SLMATH_SUB_PS(SLMATH_SETZERO_PS(),m128()), m128()) );
}

inline vec4 vec4::neg()const
{
	return -*this;
}

inline vec4 vec4::mix(const vec4& y, float a )const
{
	return vecMix( *this, y, a );
}

inline vec4 vec4::clamp(const vec4& min, const vec4& max )const
{
	return vecClamp( *this, min, max );
}

inline vec4 vec4::saturate()const
{
	return vecSaturate(*this);
}

inline bool vec4::check()const
{
#ifdef SLMATH_SIMD
	SLMATH_VEC_ASSERT( 0 == (reinterpret_cast<size_t>(&v.x)&0xF) ); // 16B aligned?
#endif
	return x<=FLT_MAX && x>=-FLT_MAX && y<=FLT_MAX && y>=-FLT_MAX && z<=FLT_MAX && z>=-FLT_MAX && w<=FLT_MAX && w>=-FLT_MAX;
}

inline vec4 vec4::add(const vec4& b )const
{
	return *this+b;
}

inline vec4 vec4::sub(const vec4& b )const
{
	return *this-b;
}

inline vec4 vec4::mul(float b )const
{
	return *this*b;
}

#ifdef SLMATH_AUTO_DX_CONVERSION
inline vec4& vec4::operator = (const D3DXVECTOR4& dxv4)
{
	this->x = dxv4.x;
	this->y = dxv4.y;
	this->z = dxv4.z;
	this->w = dxv4.w;
	return *this;
}

inline vec4::operator D3DXVECTOR4()const
{
	return D3DXVECTOR4(x, y, z, w);
}
#endif // SLMATH_AUTO_DX_CONVERSION

inline vec4 max( const vec4& a, const vec4& b )
{
	return vec4( SLMATH_MAX_PS(a.m128(),b.m128()) );
}

inline vec4 min( const vec4& a, const vec4& b )
{
	return vec4( SLMATH_MIN_PS(a.m128(),b.m128()) );
}

inline bool check( const vec4& v )
{
	return v.check();
}

inline std::ostream& operator << (std::ostream& stream, const vec4& v)
{
	stream << "vec4(" << v.x << "," << v.y << "," << v.z << "," << v.w << ")";
	return stream;
}

inline std::wostream& operator << (std::wostream& stream, const vec4& v)
{
	stream << L"vec4(" << v.x << L"," << v.y << L"," << v.z << L"," << v.w << L")";
	return stream;
}

inline vec4 operator * (float fv, const vec4& v4)
{
	return v4.mul(fv);
}

// This file is part of 'slm' C++ library. Copyright (C) 2009 Jani Kajala (kajala@gmail.com). See http://sourceforge.net/projects/slm/
